package ru.dcsearch.indexer;

/***************************************************************************
 *   Modified by TMC
 *   berechitai@gmail.com
 *
 *   This file is part of DC Indexer project
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 ***************************************************************************/
/*
 * This file is part of Mobile DC.
 */

/* DCJavaClient - a DirectConnect client written in Java
 * Copyright (C) 2001 Stefan Görling, stefan@gorling.se
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

// $Id: DCEncryptionHandler.java,v 1.7 2001/10/28 18:18:01 creator Exp $


/**
 * This clas handles Encryption, i.e. we load the padding and replacement values and calculates responses on demand.
 * This class calculates the challenge-response process.
 *
 * Eric Prevoteau <www@ac2i.tzo.com> did break the algorithm in a nicer way, I had a table of padding and replacement values which i used to calculate the key. Eric went one step longer and found the pattern within the numbers, and found a nibble swap. Therefore his algorithm will live on for eternity and mine will be forever forgotten... :) / Stefan
 */
class DCEncryptionHandler {


    public DCEncryptionHandler()
    {

    }

    /***

     This is where the magic happends, it takes a string, applies magic and there is a response to the challenge.

     ***/


    public String calculateValidationKey(String validationString) {

        /*
          This code snippet is stolen and translated into java by Stefan from the DCTC (Direct Connect Text Client) package,
          Se above for further explanation why...
         */

        /*************************************************************************/
        /* the key is quite easily :) computed from the lock                     */
        /* key[x]= ns(lock[x]^lock[x-1])		                         */
        /*   ns is a nibble swap (switch the upper 4 bits with the lower 4 bits) */
        /* exception:                                                            */
        /* key[0] is a bit different                                             */
        /* let's name A and B the 2 last bytes of the lock                       */
        /* key[0]= ns(lock[0]^A^B^0x05)         ; 0x05 is a kind of magic nibble */
        /*************************************************************************/


        StringBuffer key = new StringBuffer();
        int i;
        int u,l,o;
        int v;
        int lockLength = validationString.length();

        /* first byte is a special case */
        u = (int) validationString.charAt(0);
        l = (int) validationString.charAt(lockLength - 1);
        o = (int) validationString.charAt(lockLength - 2);

        /* do xor */
        u = u ^ l ^ o ^ 0x05;		/* don't forget the magic 0x5 */

        /* do nibble swap */
        v = (((u << 8) | u) >> 4) & 255;
        key.append((char) v);

        /* all other bytes use the same code */
        for (i = 1; i < lockLength; i++) {
            u = (int) validationString.charAt(i);
            l = (int) validationString.charAt(i - 1);

            /* do xor */
            u = u ^ l;

            /* do nibble swap */
            v = (((u << 8) | u) >> 4) & 255;

            key.append((char) v);
        }
        return encodeValidationKey(key.toString());

    }

    /***
     Some characters are reserved, therefore we escape them using a wieard esceaping method.
     ***/

    private String encodeValidationKey(String key) {
        StringBuffer safeKey = new StringBuffer();
        for (int i = 0; i < key.length(); i++) {
            char c = key.charAt(i);


            if (c == 124)
                safeKey.append("/%DCN").append((int) c).append("%/");
            else if (c == 36)
                safeKey.append("/%DCN0").append((int) c).append("%/");
            else if (c == 126)
                safeKey.append("/%DCN").append((int) c).append("%/");
            else if (c == 96)
                safeKey.append("/%DCN0").append((int) c).append("%/");
            else if (c == 5)
                safeKey.append("/%DCN00").append((int) c).append("%/");
            else if (c == 0)
                safeKey.append("/%DCN00").append((int) c).append("%/");
            else
                safeKey.append(c);
        }
        return safeKey.toString();
    }

}
